/**
 * File JadeContainerFactory.java created by Pablo Díaz Fernández
 * on 28/10/2011 for the project supply-chain-simulator
 */
package org.lsk.pfc.scsim.model;

import java.io.IOException;
import java.lang.reflect.Constructor;

import org.apache.commons.lang.ArrayUtils;
import org.lsk.pfc.scsim.model.agent.InformationAgent;
import org.lsk.pfc.scsim.model.exception.ContainerException;
import org.lsk.pfc.scsim.model.exception.MASCreationException;
import org.lsk.pfc.scsim.model.mas.MultiAgentSystem;
import org.lsk.pfc.scsim.model.util.ConstantKeys;
import org.lsk.pfc.scsim.model.util.NetworkHelper;

import jade.core.Agent;
import jade.core.Profile;
import jade.core.ProfileImpl;
import jade.core.Runtime;
import jade.wrapper.AgentController;
import jade.wrapper.ContainerController;
import jade.wrapper.StaleProxyException;

/**
 * @author Pablo Díaz Fernández
 * 
 */
public final class JadeContainerFactory {

	/**
	 * Singleton instance.
	 */
	private static JadeContainerFactory instance;

	/**
	 * Default container of the factory.
	 */
	private static ContainerController defaultContainer;

	/**
	 * Constructor of the class. Creates a default profile that is used to
	 * create the container in localhost:1099
	 * 
	 * @throws ContainerException
	 *             Exception creating container factory.
	 */
	private JadeContainerFactory() throws ContainerException {
		Runtime rt = Runtime.instance();
		Profile defaultProfile;
		try {
			defaultProfile = new ProfileImpl(NetworkHelper.getLocalIP(), -1,
			        null);
		} catch (IOException e) {
			throw new ContainerException(e);
		}
		defaultContainer = rt.createAgentContainer(defaultProfile);
	}

	/**
	 * Gets the instance of the singleton class.
	 * 
	 * @return the instance
	 * @throws ContainerException
	 *             Exception creating container factory.
	 */
	public static JadeContainerFactory getInstance() throws ContainerException {
		if (instance == null) {
			instance = new JadeContainerFactory();
		}
		return instance;
	}

	/**
	 * Gets the default container of the factory.
	 * 
	 * @return the defaultContainer
	 */
	public ContainerController getDefaultContainer() {
		return defaultContainer;
	}

	/**
	 * Gets a new container for the host, port and platformID specified.
	 * 
	 * @param host
	 *            Host in which the container is created, <code>null</code> if
	 *            default.
	 * @param port
	 *            port number in which the container is created, -1 if default.
	 * @param platformID
	 *            Id of the platform where the container is created,
	 *            <code>null</code> if default.
	 * @return the container created.
	 */
	public static ContainerController getContainer(final String host,
	        final int port, final String platformID) {
		Runtime rt = Runtime.instance();
		Profile defaultProfile = new ProfileImpl(host, port, platformID);
		return rt.createAgentContainer(defaultProfile);
	}

	public static MultiAgentSystem createNewMAS(final ContainerController cc,
	        final String masName, final Class<MultiAgentSystem> stage)
	        throws MASCreationException {
		try {
			Constructor<MultiAgentSystem> masConstructor = stage
			        .getConstructor(String.class, ContainerController.class);
			return masConstructor.newInstance(masName, cc);
		} catch (Exception e) {
			throw new MASCreationException(masName, e);
		}
	}

	/**
	 * Creates an agent of the specified class in the specified container.
	 * 
	 * @param cc
	 *            Container in which the agent is going to be created.
	 * @param masName
	 *            Multi agent system of the agent.
	 * @param suffix
	 *            Suffix of the name of the agent. Is related to the sort of
	 *            agent that is going to be created.
	 * @param clazz
	 *            {@link Class} of the agent to create.
	 * @param params
	 *            Array of parameters to send to the agent.
	 * @return {@link AgentController} for the agent created.
	 * @throws StaleProxyException
	 *             Exception creating the agent.
	 */
	public static AgentController createNewAgent(final ContainerController cc,
	        final String masName, final String suffix,
	        final Class<Agent> clazz, final Object[] params)
	        throws StaleProxyException {

		return cc.createNewAgent(masName + suffix, clazz.getCanonicalName(),
		        ArrayUtils.add(params, 0, masName));
	}

}
